/*
 * ESP8266-MQTT透传工具
 * Designed by ZhangHao
 * 2018.8.16
 * 
 * Note:
 * 远程串口  用于项目：超声波电源
 * 实现消息的透明转发，无其他功能
 * 详见ReadMe.md文件
 */

/*
include files
*/
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>

#define statePin 5  //高电平网络畅通  低电平网络故障

//WIFI信息，可由串口修改
const char *ssid = "LAB404";
const char *password = "404404404";
const char *mqtt_server = "39.96.17.63"; //EMQ
const char *inTopic = "smartPowerIn";
const char *outTopic = "smartPowerOut";

//Global variables 全局变量
WiFiClient espClient;
PubSubClient client(espClient);

//Wifi初始化，连接到路由器
void setup_wifi()
{
  delay(10);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
  }
  randomSeed(micros());
}

//OTA升级  参数为要升级的文件路径
void OTA_Update(char *url)
{
  //如果url为0，则使用默认固件
  if (url[0] == 0)
  {
    sprintf(url, "http://39.106.187.215/Smart_power/Smart_power.bin");
  }
  t_httpUpdate_return ret = ESPhttpUpdate.update(url);
  switch (ret)
  {
  case HTTP_UPDATE_FAILED:
    Serial.println("[update] Update failed.");
    break;
  case HTTP_UPDATE_NO_UPDATES:
    Serial.println("[update] Update no Update.");
    break;
  case HTTP_UPDATE_OK:
    Serial.println("[update] Update ok."); // may not called we reboot the ESP
    break;
  }
}

//MQTT消息的回调函数，用来处理收到的消息
void callback(char *topic, byte *payloadbyte, unsigned int length)
{
  char payload[400] = {'\0'};

  if (length > 400)
    return;
  //向串口打印收到的消息
  for (unsigned int i = 0; i < length; i++)
  {
    payload[i] = (char)payloadbyte[i];
    Serial.print((char)payload[i]);
  }
  //空中升级
  if(payload[1] == 'O' && payload[2] == 'T' && payload[3] == 'A'){
    OTA_Update(0);
  }
}

//MQTT自动重连函数
void reconnect()
{
  // Loop until we're reconnected
  while (!client.connected())
  {
    // Create a random client ID
    String clientId = "Smart_Power_Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str()))
    {
      // Once connected, publish an announcement...
      client.publish("infoTopic", "Smart_light Online now.");
      // ... and resubscribe
      client.subscribe(inTopic);
    }
    else
    {
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup()
{
  pinMode(statePin,OUTPUT);
  digitalWrite(statePin,LOW);
  //初始化串口
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883); //连接服务器
  client.setCallback(callback);        //设置回调函数
}

void loop()
{
  char temp[400] = {'\0'};
  if(Serial.available()){
    delay(100);
    int numdata = Serial.available();  
    for(int i = 0;i < numdata; i++){
      temp[i] = Serial.read();
    }
    while(Serial.read()>=0){} //清空串口缓存
    if(temp[0] == '{' && temp[numdata-1] == '}'){
      client.publish(outTopic,temp);
    } else {
      client.publish("infoTopic",temp);
    }

  }
  if (!client.connected())
  { //检查是否掉线，自动重连
    digitalWrite(statePin,LOW);
    reconnect();
  }
  digitalWrite(statePin,HIGH);
  client.loop();
}
